<%page expression_filter="trim"/>
<%! 
    def get(xp, node) :
        res = node.xpathEval(xp)
        if len(res)==0 :
            return None
        return res[0].getContent()
    
    def trueFalse(x) :
        if x :
            return 'true'
        else :
            return 'false'
        
    def doFinalize(finalize) :
        return '\n'.join(finalize)

    def doCall(argnames, node) :
        return get("cname/text()", node) + '(' + ', '.join(argnames) + ')'
%>    
    

<%def name="errorCheck(node, finalize)">
    if (error) {
        ${doFinalize(finalize)}
        return NULL;
    }        
</%def>
    
<%def name="beginParams(node, finalize)">
    int args_used = 0;
    bool error = false;
    func_context context;
    init_context(&context);
</%def>
    
<%def name="endParams(node, finalize)">
    test_remaining_arg(args, &args_used, &error);
    ${errorCheck(node, finalize)}
</%def>

<%def name="param(node, argnames, finalize)">
    <%
        type = get("type/text()", node)
        default = get("default/text()", node)
        arg = 'arg'+str(len(argnames))
        argnames.append(arg)
        defaultargsOn = trueFalse(default)
        if default==None :
            if type in ['gen', 'reference', 'expression-inline'] :
                default = 'NULL'
            elif type in ['chars-parsed', 'chars-unparsed', 'string'] :
                default = '"0"'
            elif type=='variable-number' :
                default = '-1'
            elif type=='long' :
                default = '0'
    %>
    % if type=='gen':
            GEN ${arg} = get_GEN_arg(args, &args_used, \
                        ${defaultargsOn}, ${default}, &error);
    % elif type=='variable-number':
            long ${arg} = get_var_arg(args, &args_used, \
                        ${defaultargsOn}, ${default}, &error);
    % elif type=='variable-entree':
            entree* ${arg} = get_var_entree_arg(args, &args_used, &error);
    % elif type=='local-variable-entree':    
            entree* ${arg} = get_ref_var_arg(&context, args, &args_used, &error);
    % elif type=='long':    
            long ${arg} = get_long_arg(args, &args_used, \
                        ${defaultargsOn}, ${default}, &error);
    % elif type in ['chars-parsed', 'chars-unparsed']:
            char* ${arg} = (char*) get_char_arg(args, &args_used, 
                        ${defaultargsOn}, ${default}, &error);
    % elif type in ['expression-inline', 'expression-eval']:
            <% long_expression = trueFalse(type=='expression-eval') %>
            char* ${arg} = get_eval_arg(&context, args, &args_used, 
                        ${long_expression}, &error);
    % elif type=='string':    
            GEN ${arg} = get_string_arg(args, &args_used, 
                        ${defaultargsOn}, ${default}, &error);
    % elif type=='reference':    
            GEN _${arg} = NULL;
            PyObject* ref_${arg} = get_ref_arg(args, &args_used, \
                        ${defaultargsOn}, ${default}, &error);
            GEN* ${arg} = NULL;            
            if(ref_${arg}!=NULL) {
                ${arg} = &_${arg};
            }
    % elif type=='precision-real':
            long ${arg} = get_real_precision();
    % elif type=='precision-series':
            long ${arg} = get_series_precision();
    % endif
    ${errorCheck(node, finalize)}
    <%
        if type in ['local-variable-entree', 'expression-inline', 'expression-eval']:
            finalize.append('free(' + arg + ');')
        elif type=='reference':
            finalize.append('copy_reference(ref_' + arg + ', _' + arg + ');')
    %>
</%def>

<%def name="caller(argnames, node, finalize)">
    CATCH_PARI {
        SET_ERROR;
        ${doFinalize(finalize)}
        return NULL;
    } TRY_PARI {
        <% returnType = get("prototype/return/text()", node) %>
        % if returnType=='gen':
            PyObject* res = (PyObject*) create_gen(${doCall(argnames, node)});
        % elif returnType=='void':
            ${doCall(argnames, node)};
            PyObject* res = Py_None;
            Py_INCREF(Py_None);
        % elif returnType=='long' or returnType=='int':
            PyObject* res = PyInt_FromLong(${doCall(argnames, node)});
        % else:
            <% raise SyntaxError, 'wrong return type '+returnType %>
        % endif
        ${doFinalize(finalize)}
        return res;
    } ENDCATCH_PARI        
</%def>
    
<%def name="function(node)">
static PyObject* 
paricore_${get("gpname/text()", node)} (PyObject*, PyObject* args) {
    pari_sp __av = avma;   
    <% finalize = ["avma = __av;"] %>
    <% argnames = [] %>
    ${beginParams(node, finalize)}
    % for paramNode in node.xpathEval("prototype/param"):
        ${param(paramNode, argnames, finalize)}
    % endfor
    ${endParams(node, finalize)}
    ${caller(argnames, node, finalize)}
}
</%def>

<%def name="declaration(node)">
    <%
        gpname = get("gpname/text()", node)
        help = get("help/text()", node)
        help = help.replace('\n', ' ')
        help = help.replace('\\', '\\\\')
        help = help.replace('"', '\\"')
    %>
    {"${gpname}", paricore_${gpname},  METH_VARARGS, "${help}"},
</%def>


<%def name="header()">
/* This file is autogenerated from the database. */
/* See src/pari-functions.mako.cpp */
/* Do not edit*/
</%def>

${header()}
% for node in root.xpathEval("/pari-functions/function[cname and gpname and prototype]"):
    %if get('class/text()', node) in ['basic']:
        %if implementation:
            ${function(node)}
        %else:
            ${declaration(node)}
        %endif
    %endif
%endfor

